﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace BusinessTier
{
    /// <summary>
    /// The business class that encapsulates all of the properties and behaviour
    /// of a maze-game Player.
    /// </summary>
    public class Player
    {
        private string username;
        private MazeServer game;
        private Point coordinates;

        /// <summary>
        /// The username property of this player.
        /// </summary>
        public string Username { get { return username; } }

        /// <summary>
        /// Constructs a new player attached to the specified game.
        /// </summary>
        /// <param name="username"></param>
        /// <param name="mazeServerKey"></param>
        public Player(String username, string mazeServerKey)
        {
            if (username == null) throw new ArgumentNullException("username", "The player's username cannot be null.");
            else if (mazeServerKey == null) throw new ArgumentNullException("mazeServerKey", "A valid, non-null maze server key must be provided.");
            else
            {
                game = MazeServerFactory.getMazeServer(mazeServerKey); // identify and add a reference to the game
                game.eventHappened += new MazeServer.EventHappened(MazeServer_eventHappened); // add the custom defined event handler
                this.username = username;
                this.notifications = new List<GameEvent>();
            }
        }

        /// <summary>
        /// Custom defined handler for maze-game events.
        /// </summary>
        /// <param name="e">The event that has occurred and is passed in by the notifier</param>
        void MazeServer_eventHappened(GameEvent e)
        {
            notifications.Add(e);
            switch (e.Type)
            {
                case GameEventType.Move:
                    coordinates.X++;
                    coordinates.Y++;
                    break;
                default:
                    break;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        private List<GameEvent> notifications;
        /// <summary>
        /// 
        /// </summary>
        /// <param name="number"></param>
        /// <returns></returns>
        public IList<IDictionary<string, object>> getNotifications(int number)
        {
            if (number < 0) throw new ArgumentNullException("number", "Number cannot be null");
            int to = (number > notifications.Count) ? notifications.Count : number;
            IList<GameEvent> selectedNotifications = notifications.GetRange(0, number);
            IList<IDictionary<string, object>> events = new List<IDictionary<string, object>>();
            foreach (GameEvent e in selectedNotifications)
            {
                events.Add(e.GetAllData());
            }
            return events;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public bool isNotificationsGreaterThanZero()
        {
            return (notificationCount > 0);
        }

        /// <summary>
        /// 
        /// </summary>
        private int notificationCount = 0;
        /// <summary>
        /// 
        /// </summary>
        public int NotificationCount { get { return notificationCount; } }
    }

    /// <summary>
    /// A utility class that represents Cartesian Points. These are often also 
    /// referred to as Cartesian coordinates, planar coordinates, XY pairs, 
    /// XY tuplets or ordered pairs. 
    /// 
    /// Cartesian coordinates contain two read-write properties, an X coordinate 
    /// value and a Y coordinate value.
    /// </summary>
    public struct Point
    {
        private int x; // the x (horizontal) parameter
        private int y; // the y (vertical) parameter

        /// <summary>
        /// Returns the X coordinate of this cartesian point, as an integer value.
        /// </summary>
        public int X { get { return x; } set { x = value; } }
        /// <summary>
        /// Returns the y coordinate of this cartesian point, as an integer value.
        /// </summary>
        public int Y { get { return y; } set { y = value; } }

        /// <summary>
        /// Constructs a Point from a cartesian XY coordinate pair specified as integers.
        /// </summary>
        /// <param name="x">the x dimension, or coordinate, of this point</param>
        /// <param name="y">the y dimension, or coordinate, of this point</param>
        public Point(int x, int y)
        {
            this.x = x;
            this.y = y;
        }

        /// <summary>
        /// Attempts to construct a Point from a string containing a cartesian 
        /// XY coordinate pair provided it is expressed in the accepted JSON-like syntax.
        /// </summary>
        /// <param name="pointString">The string containing correctly formatted XY coordinates of this point</param>
        public Point(string pointString)
        {
            string[] temp = pointString.Split(new[] { 'X', 'Y', ':' });
            this.x = int.Parse(temp[0]);
            this.y = int.Parse(temp[1]);
        }

        /// <summary>
        /// Returns a string representation of this point, containing the X and Y
        /// coordinate values in a format that is compatible with the Point(string)
        /// form constructor.
        /// 
        /// The general form of the returned string is "X:[xValue]Y:[yValue]"
        /// where xValue and yValue are replaced with the integer x and y
        /// coordinate properties of the point. In other words, calling
        /// new Point(this.ToString()) will result in the creation of a copy of
        /// this point.
        /// </summary>
        /// <returns>A string representation of this Cartesian Point</returns>
        public override string ToString()
        {
            return "X:" + X + "Y:" + Y;
        }
    }
}
